Portfólio Thiago Gonçalves Custódio

Com o rápido desenvolvimento da indústria de telecomunicações, os provedores de serviços estão mais inclinados à expansão da base de assinantes. Para atender à necessidade de sobreviver no ambiente competitivo, a retenção dos clientes existentes tornou-se um grande desafio. Afirma-se que o custo de adquirir um novo cliente é muito maior do que o de manter o existente. Portanto, é imperativo que as indústrias de telecomunicações usem análises avançadas para entender o comportamento do consumidor e, por sua vez, prever a associação dos clientes quanto à sua saída ou não da empresa.
Este conjunto de dados é de domínio público e contém informações de nível de cliente para uma empresa de telecomunicações. Vários atributos relacionados aos serviços utilizados são registrados para cada cliente.
Objetivo: Neste projeto iremos utilizar a linguagem Python, para criar um modelo de aprendizagem de máquina que possa prever se um cliente pode ou não cancelar seu plano, e qual a probabilidade de isso ocorrer.
Começaremos nosso projeto, importanto todas as bilbiotecas necessárias, para a realização das fases iniciais de exploração, e transformação dos dados (Data Munging).
# Importando biblioteca, para ocultar Future Warnings.
import warnings
warnings.simplefilter(action = 'ignore', category = FutureWarning)
# Importando bibliotecas, para a manipulação e exploração dos conjuntos de dados.
import numpy as np
import pandas as pd
# Importando módulos utilitários para Análise Exploratória/Estatística, Pré-processamento/Feature Selection e Modelagem preditiva.
import utilAnaExplor as utlex
import utilScaleTransf as utlst
import utilPcaTransf as utlpca
import utilMachineLearning as utlml
# Importando bibliotecas, para balanceamento de classes e divisão do dataset.
from imblearn.over_sampling import SMOTE
# Importando classes e bibliotecas necessárias para a etapa de pré-processamento dos dados.
from sklearn.preprocessing import MinMaxScaler, PowerTransformer, normalize, LabelEncoder, StandardScaler
# Importando bibliotecas, para a etapa de modelagem preditiva.
from sklearn.feature_selection import SelectKBest, SelectPercentile, mutual_info_classif, f_classif, RFE, chi2
from mlxtend.feature_selection import SequentialFeatureSelector as SFS
import xgboost as xgb
from sklearn.ensemble import RandomForestClassifier, ExtraTreesClassifier, AdaBoostClassifier, GradientBoostingClassifier
import xgboost as xgb
from sklearn import tree
from sklearn.svm import SVC
from sklearn.naive_bayes import GaussianNB
from sklearn.tree import DecisionTreeClassifier
from sklearn.neighbors import KNeighborsClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import KFold, cross_val_score
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
from sklearn.ensemble import RandomForestClassifier, ExtraTreesClassifier, AdaBoostClassifier, GradientBoostingClassifier
# Importando classe, para fazer a busca dos melhores parâmetros, a serem utilizados em cada um dos modelos treinados.
from sklearn.model_selection import GridSearchCV
# Importando classes, para calcular as métricas de avaliação dos modelos preditivos.
from sklearn.metrics import accuracy_score, balanced_accuracy_score, average_precision_score, precision_score
from sklearn.metrics import recall_score, f1_score, roc_auc_score, cohen_kappa_score
# Versões dos pacotes usados neste jupyter notebook
%reload_ext watermark
%watermark -a "Thiago Gonçalves Custódio" --iversions
# Carregando dados de treino.
dataTrain = pd.read_csv('datasets/projeto4_telecom_treino.csv')
# Exibindo as primeiras linhas do DataFrame.
dataTrain.head()
# Carregando dados de teste.
dataTest = pd.read_csv('datasets/projeto4_telecom_teste.csv')
# Exibindo as primeiras linhas do DataFrame.
dataTest.head()
Iremos definir algumas funções, para facilitar a execução das etapas de Data Munging.
# Definindo uma função, para converter variáveis para o tipo categórico, e criar suas respectivas versões dummy.
def categoryToDummyVariables(data, columnsName):
# Criando um dicionário vazio.
newTypes = dict()
# Criando o nome das variáveis dummy.
newColumnsName = [n + '_dummy' for n in columnsName]
# Definindo que cada variável especificada, deve ser convertida para o tipo de dado categórico.
for i in range(0, len(columnsName)):
newTypes.update({columnsName[i]: 'category'})
# Convertendo o tipo de dado das variáveis especificadas.
data = data.astype (newTypes)
# Criando variáveis dummy.
for i in range(0, len(columnsName)):
data[newColumnsName[i]] = data[columnsName[i]].cat.codes
# Retornando o DataFrame modificado.
return data
# Definindo uma função, para realizar as tarefas de Data Munging, necessárias para o conjunto de dados em análise.
def organizeData(data):
# Extraindo o código de área da variável area_code.
data['area_code'] = data['area_code'].apply(lambda e: e.split('_')[2]).astype('category')
# Criando variáveis dummy para o conjunto de dados.
data = categoryToDummyVariables(data = data, columnsName = data.select_dtypes(include = object).columns)
# Eliminando a variável de índice do conjunto de dados.
data = data.drop(columns = data.columns[0], axis = 1)
# Retornando o DataFrame modificado.
return data
# Verificando as dimensões do dataset de treino.
dataTrain.shape
Verificamos a existência de 21 variáveis, e 3.333 observações dentro do dataset de treino.
# Verificando o número de registros duplicados.
dataTrain.duplicated().sum()
Não há registros duplicados no dataset de treino.
# Verificando o número de NAs existentes dentro do dataset de treino.
dataTrain.isna().sum()
Não foi detectado nenhum valor NA dentro do conjunto de dados.
# Verificando o tipo de dados das variáveis do dataset.
dataTrain.dtypes.value_counts()
# Contabilizando o número de valores únicos, em cada variável do dataset de treino.
info = dataTrain.nunique().sort_values()
# Determinando o tipo de dado, de cada uma das variáveis, do dataset de treino.
info = pd.DataFrame(info.values, index = info.index, columns = ['NUniques'])
# Atribuindo informações, sobre o tipo de dado das variáveis, ao DataFrame.
info['dtypes'] = dataTrain.dtypes
# Exibindo DataFrame.
info
# Verificando as dimensões do dataset de teste.
dataTest.shape
Verificamos a existência de 21 variáveis, e 1.667 observações dentro do dataset de teste.
# Verificando o número de IDs duplicados.
dataTest.duplicated().sum()
Não há registros duplicados no dataset de teste.
# Verificando o número de NAs existentes dentro do dataset de teste.
dataTest.isna().sum()
Não foi detectado nenhum valor NA dentro do conjunto de dados.
# Verificando o tipo de dados das variáveis do dataset.
dataTest.dtypes.value_counts()
# Contabilizando o número de valores únicos, em cada variável do dataset de treino.
info = dataTest.nunique().sort_values()
# Determinando o tipo de dado, de cada uma das variáveis, do dataset de treino.
info = pd.DataFrame(info.values, index = info.index, columns = ['NUniques'])
# Atribuindo informações, sobre o tipo de dado das variáveis, ao DataFrame.
info['dtypes'] = dataTest.dtypes
# Exibindo DataFrame.
info
Iremos extrair o código de área para a variável area_code e convertê-la para o tipo de dado numérico. Também criaremos variáveis dummy para aquelas que forem do tipo categórico. Por fim, eliminaremos a coluna de índices do conjunto de dados.
Aplicaremos este processo para os dados de treino e de teste.
# Limpando e organizando o conjunto de dados de treino.
dataTrain = organizeData(data = dataTrain)
# Limpando e organizando o conjunto de dados de teste.
dataTest = organizeData(data = dataTest)
O coeficente de Assimetria (Skewness), indica como os dados estão distribuídos, e para interpretar seu resultado podemos olhar a tabela a seguir:
| Índice de Assimetria | Descrição: |
|---|---|
| SK ≈ 0 | Os dados são simétricos. Tanto a cauda do lado direito, quanto a do lado esquerdo da função densidade de probabilidade, são iguais; |
| SK < 0 | A assimetria é negativa. A cauda do lado esquerdo da função densidade de probabilidade, é maior que a do lado direito e; |
| SK > 0 | A assimetria é positiva. A cauda do lado direito da função densidade de probabilidade, é maior que a do lado esquerdo. |
O coeficiente de Curtose (Kurtosis), é uma medida que caracteriza o achatamento da curva da função de distribuição, e para interpretar seu resultado, podemos olhar a tabela a seguir:
| Índice de Curtose | Descrição: |
|---|---|
| CK ≈ 0 | A distribuição é normal, e é chamada de Curtose Mesocúrtica; |
| CK < 0 | A Cauda é mais leve que a normal. Para um coeficiente de Curtose negativo, tem-se uma Curtose Platicúrtica e; |
| CK > 0 | A Cauda é mais pesada que a normal. Para um coeficiente de Curtose positivo, tem-se uma Curtose Leptocúrtica. |
# Definindo o nome da variável a ser analisada.
col = 'churn'
# Definindo a descrição da variável nos gráficos.
label = 'Churn'
# Contabilizando a frequência absoluta, de cada categoria presente na variável especificada.
dataCounts = dataTrain[col].value_counts()
# Plotando um gráfico de barras para a variável especificada.
utlex.plotBar (
data = dataCounts,
title = 'Frequência absoluta das categorias da Feature ' + col,
yaxis = 'Frequência Absoluta',
xaxis = label
)
# Plotando um gráfico de pizza para a variável especificada.
utlex.plotPie (
data = dataCounts,
title = 'Frequência relativa das categorias da feature ' + col
)
Apenas 14,5 % dos registros referem-se a clientes que efetuaram o churn. Nossa variável target esta desbalanceada, trataremos tal desvio mais a frente.
# Definindo o nome da variável a ser analisada.
col = 'state'
# Definindo o nome da variável Target.
target = 'churn'
# Definindo a descrição da variável nos gráficos.
label = 'Estados'
# Capturando variáveis especificadas do Dataset.
data = dataTrain[[col, target]]
# Criando uma variável count para contabilizar as ocorrências de cada registro.
data['count'] = 1
# Agrupando dados e contabilizando o número de ocorrências.
data = data.groupby(by = [target, col]).sum()
# Reorganizando DataFrame.
data = data.reset_index()
# Plotando um gráfico de barras para a variável especificada.
utlex.plotBar (
data = data,
col = col,
target = target,
title = 'Churn dos clientes por ' + label,
yaxis = 'Frequência Absoluta',
xaxis = label,
kind = 'groups'
)
Os estados do Texas (TX), New Jersey (NJ) e Maryland (MD) são os que apresentam as maiores quantidades de registros de clientes que realizaram o churn.
# Definindo o nome da variável a ser analisada.
col = 'account_length'
# Definindo o nome da variável Target.
target = 'churn'
# Definindo a descrição da variável nos gráficos.
label = 'Tamanho da Conta'
# Capturando variáveis especificadas do Dataset.
data = dataTrain[[col, target]]
# Criando uma variável count para contabilizar as ocorrências de cada registro.
data['count'] = 1
# Agrupando dados e contabilizando o número de ocorrências.
data = data.groupby(by = [target, col]).sum()
# Reorganizando DataFrame.
data = data.reset_index()
# Plotando um gráfico de histograma para a variável especificada.
utlex.plotHist (
data = dataTrain[[col, target]],
title = 'Histograma para a variável ' + col,
xaxis = label,
yaxis = 'Frequência Absoluta',
col = col,
target = target,
groups = True
)
# Criando um gráfico de Densidade para a variável especificada.
utlex.plotDensity (
data = dataTrain[[col, target]],
title = 'Gráfico de Densidade para a variável ' + col,
xaxis = label,
col = col,
target = target,
group = True
)
A distribuição do tamanho da conta, para os indivíduos que fizeram ou não o churn, é aproximandamente igual.
# Plotando um gráfico de boxplot para a variável especificada.
utlex.plotBoxplot (
data = dataTrain[[col, target]],
title = 'Boxplot para a variável ' + col,
yaxis = label,
xaxis = target.capitalize(),
col = col,
target = target,
kind = 'groups'
)
O tamanho mediano, das contas dos indivíduos que realizaram o churn, é ligeiramente maior do que o daqueles que não o efeturam.
# Calculando algumas estatísticas para a variável especificada.
utlex.varStats(col = col, data = dataTrain, target = target)
Destacamos que:
# Definindo o nome da variável a ser analisada.
col = 'area_code'
# Definindo o nome da variável Target.
target = 'churn'
# Definindo a descrição da variável nos gráficos.
label = 'Código de Área'
# Capturando variáveis especificadas do Dataset.
data = dataTrain[[col, target]]
# Criando uma variável count para contabilizar as ocorrências de cada registro.
data['count'] = 1
# Agrupando dados e contabilizando o número de ocorrências.
data = data.groupby(by = [target, col]).sum()
# Reorganizando DataFrame.
data = data.reset_index()
# Transformando variável alvo em String.
data[col] = data[col].apply(lambda c: str(c) + ' Code')
# Plotando um gráfico de barras para a variável especificada.
utlex.plotBar (
data = data,
col = col,
target = target,
title = 'Churn dos clientes por ' + label,
yaxis = 'Frequência Absoluta',
xaxis = label,
kind = 'groups'
)
O código de área 415, é o que apresenta o maior número de registros para os clientes que realizaram o churn.
# Definindo o nome da variável a ser analisada.
col = 'international_plan'
# Definindo o nome da variável Target.
target = 'churn'
# Definindo a descrição da variável nos gráficos.
label = 'Plano Internacional'
# Capturando variáveis especificadas do Dataset.
data = dataTrain[[col, target]]
# Criando uma variável count para contabilizar as ocorrências de cada registro.
data['count'] = 1
# Agrupando dados e contabilizando o número de ocorrências.
data = data.groupby(by = [target, col]).sum()
# Reorganizando DataFrame.
data = data.reset_index()
# Capitalizando valores da variável alvo.
data[col] = data[col].apply(lambda c: c.capitalize())
# Plotando um gráfico de barras para a variável especificada.
utlex.plotBar (
data = data,
col = col,
target = target,
title = 'Churn dos clientes por ' + label,
yaxis = 'Frequência Absoluta',
xaxis = label,
kind = 'groups'
)
A proporção de clientes que utilizam o plano internacional, e fizeram ou não o churn, é aproximadamente igual.
# Definindo o nome da variável a ser analisada.
col = 'voice_mail_plan'
# Definindo o nome da variável Target.
target = 'churn'
# Definindo a descrição da variável nos gráficos.
label = 'Plano de Correio de Voz'
# Capturando variáveis especificadas do Dataset.
data = dataTrain[[col, target]]
# Criando uma variável count para contabilizar as ocorrências de cada registro.
data['count'] = 1
# Agrupando dados e contabilizando o número de ocorrências.
data = data.groupby(by = [target, col]).sum()
# Reorganizando DataFrame.
data = data.reset_index()
# Capitalizando valores da variável alvo.
data[col] = data[col].apply(lambda c: c.capitalize())
# Plotando um gráfico de barras para a variável especificada.
utlex.plotBar (
data = data,
col = col,
target = target,
title = 'Churn dos clientes por ' + label,
yaxis = 'Frequência Absoluta',
xaxis = label,
kind = 'groups'
)
Os clientes que utilizam o plano de correio de voz, predominantemente, não realizam o churn.
# Definindo o nome da variável a ser analisada.
col = 'number_vmail_messages'
# Definindo o nome da variável Target.
target = 'churn'
# Definindo a descrição da variável nos gráficos.
label = 'Número de mensagens vmail'
# Capturando variáveis especificadas do Dataset.
data = dataTrain[[col, target]]
# Criando uma variável count para contabilizar as ocorrências de cada registro.
data['count'] = 1
# Agrupando dados e contabilizando o número de ocorrências.
data = data.groupby(by = [target, col]).sum()
# Reorganizando DataFrame.
data = data.reset_index()
# Plotando um gráfico de histograma para a variável especificada.
utlex.plotHist (
data = dataTrain[[col, target]],
title = 'Histograma para a variável ' + col,
xaxis = label,
yaxis = 'Frequência Absoluta',
col = col,
target = target,
groups = True
)
Os clientes que efeturam o churn, predominantemente, não enviam mensagens vmail.
# Criando um gráfico de Densidade para a variável especificada.
utlex.plotDensity (
data = dataTrain[[col, target]],
title = 'Gráfico de Densidade para a variável ' + col,
xaxis = label,
col = col,
target = target,
group = True
)
# Plotando um gráfico de boxplot para a variável especificada.
utlex.plotBoxplot (
data = dataTrain[[col, target]],
title = 'Boxplot para a variável ' + col,
yaxis = label,
xaxis = target.capitalize(),
col = col,
target = target,
kind = 'groups'
)
O grupo de indivíduos que não realiza o churn, apresenta uma variação maior. Também observamos, que aqueles indivíduos que realizam o churn e utilizam as mensagens vmail, são outliers.
# Calculando algumas estatísticas para a variável especificada.
utlex.varStats(col = col, data = dataTrain, target = target)
Destacamos que:
# Definindo o nome da variável a ser analisada.
col = 'total_day_minutes'
# Definindo o nome da variável Target.
target = 'churn'
# Definindo a descrição da variável nos gráficos.
label = 'Total de minutos Diários'
# Capturando variáveis especificadas do Dataset.
data = dataTrain[[col, target]]
# Criando uma variável count para contabilizar as ocorrências de cada registro.
data['count'] = 1
# Agrupando dados e contabilizando o número de ocorrências.
data = data.groupby(by = [target, col]).sum()
# Reorganizando DataFrame.
data = data.reset_index()
# Plotando um gráfico de histograma para a variável especificada.
utlex.plotHist (
data = dataTrain[[col, target]],
title = 'Histograma para a variável ' + col,
xaxis = label,
yaxis = 'Frequência Absoluta',
col = col,
target = target,
groups = True
)
O grupo dos clientes que não realizaram o churn, aparenta ter uma distribuição normal, para o total de minutos diários.
# Criando um gráfico de Densidade para a variável especificada.
utlex.plotDensity (
data = dataTrain[[col, target]],
title = 'Gráfico de Densidade para a variável ' + col,
xaxis = label,
col = col,
target = target,
group = True
)
O grupo dos clientes que realizaram o churn, aparenta ter duas modas: uma em torno de 160 minutos e outra em torno de 265 minutos.
# Plotando um gráfico de boxplot para a variável especificada.
utlex.plotBoxplot (
data = dataTrain[[col, target]],
title = 'Boxplot para a variável ' + col,
yaxis = label,
xaxis = target.capitalize(),
col = col,
target = target,
kind = 'groups'
)
O grupo de indivíduos que realizaram o churn, apresentam um total de minutos diários maior.
# Calculando algumas estatísticas para a variável especificada.
utlex.varStats(col = col, data = dataTrain, target = target)
Destacamos que:
# Definindo o nome da variável a ser analisada.
col = 'total_day_calls'
# Definindo o nome da variável Target.
target = 'churn'
# Definindo a descrição da variável nos gráficos.
label = 'Total de chamadas diárias'
# Capturando variáveis especificadas do Dataset.
data = dataTrain[[col, target]]
# Criando uma variável count para contabilizar as ocorrências de cada registro.
data['count'] = 1
# Agrupando dados e contabilizando o número de ocorrências.
data = data.groupby(by = [target, col]).sum()
# Reorganizando DataFrame.
data = data.reset_index()
# Plotando um gráfico de histograma para a variável especificada.
utlex.plotHist (
data = dataTrain[[col, target]],
title = 'Histograma para a variável ' + col,
xaxis = label,
yaxis = 'Frequência Absoluta',
col = col,
target = target,
groups = True
)
O total de chamadas diárias, parece ter uma distribuição aproximadamente normal, para o grupo de clientes que não realizaram o churn.
# Criando um gráfico de Densidade para a variável especificada.
utlex.plotDensity (
data = dataTrain[[col, target]],
title = 'Gráfico de Densidade para a variável ' + col,
xaxis = label,
col = col,
target = target,
group = True
)
O total de chamadas diárias, para o grupo dos indivíduos que realizaram o churn, aparenta ser levemente maior.
# Plotando um gráfico de boxplot para a variável especificada.
utlex.plotBoxplot (
data = dataTrain[[col, target]],
title = 'Boxplot para a variável ' + col,
yaxis = label,
xaxis = target.capitalize(),
col = col,
target = target,
kind = 'groups'
)
Há mais outliers no grupo dos clientes que não realizaram o churn.
# Calculando algumas estatísticas para a variável especificada.
utlex.varStats(col = col, data = dataTrain, target = target)
Destacamos que:
# Definindo o nome da variável a ser analisada.
col = 'total_day_charge'
# Definindo o nome da variável Target.
target = 'churn'
# Definindo a descrição da variável nos gráficos.
label = 'Carga diária Total'
# Capturando variáveis especificadas do Dataset.
data = dataTrain[[col, target]]
# Criando uma variável count para contabilizar as ocorrências de cada registro.
data['count'] = 1
# Agrupando dados e contabilizando o número de ocorrências.
data = data.groupby(by = [target, col]).sum()
# Reorganizando DataFrame.
data = data.reset_index()
# Plotando um gráfico de histograma para a variável especificada.
utlex.plotHist (
data = dataTrain[[col, target]],
title = 'Histograma para a variável ' + col,
xaxis = label,
yaxis = 'Frequência Absoluta',
col = col,
target = target,
groups = True
)
A carga diária total, do grupo de indivíduos que não realizaram o churn, aparenta ter uma distribuição normal.
# Criando um gráfico de Densidade para a variável especificada.
utlex.plotDensity (
data = dataTrain[[col, target]],
title = 'Gráfico de Densidade para a variável ' + col,
xaxis = label,
col = col,
target = target,
group = True
)
A carga diária total, do grupo de indivíduos que realizaram o churn, aparenta ter duas modas: uma em torno de 26 e outra em torno de 45.
# Plotando um gráfico de boxplot para a variável especificada.
utlex.plotBoxplot (
data = dataTrain[[col, target]],
title = 'Boxplot para a variável ' + col,
yaxis = label,
xaxis = target.capitalize(),
col = col,
target = target,
kind = 'groups'
)
A variação e a mediana da carga diária total, do grupo de indivíduos que realizaram o churn, é maior.
# Calculando algumas estatísticas para a variável especificada.
utlex.varStats(col = col, data = dataTrain, target = target)
Destacamos que:
# Definindo o nome da variável a ser analisada.
col = 'total_eve_minutes'
# Definindo o nome da variável Target.
target = 'churn'
# Definindo a descrição da variável nos gráficos.
label = 'Total de minutos à Tarde'
# Capturando variáveis especificadas do Dataset.
data = dataTrain[[col, target]]
# Criando uma variável count para contabilizar as ocorrências de cada registro.
data['count'] = 1
# Agrupando dados e contabilizando o número de ocorrências.
data = data.groupby(by = [target, col]).sum()
# Reorganizando DataFrame.
data = data.reset_index()
# Plotando um gráfico de histograma para a variável especificada.
utlex.plotHist (
data = dataTrain[[col, target]],
title = 'Histograma para a variável ' + col,
xaxis = label,
yaxis = 'Frequência Absoluta',
col = col,
target = target,
groups = True
)
O total de minutos à tarde, para o grupo de clientes que não realizaram o churn, aparenta ter uma distribuição normal.
# Criando um gráfico de Densidade para a variável especificada.
utlex.plotDensity (
data = dataTrain[[col, target]],
title = 'Gráfico de Densidade para a variável ' + col,
xaxis = label,
col = col,
target = target,
group = True
)
O total de minutos à tarde, para o grupo de clientes que realizaram o churn, aparenta ter um valor mediano maior.
# Plotando um gráfico de boxplot para a variável especificada.
utlex.plotBoxplot (
data = dataTrain[[col, target]],
title = 'Boxplot para a variável ' + col,
yaxis = label,
xaxis = target.capitalize(),
col = col,
target = target,
kind = 'groups'
)
O grupo de clientes que não realizaram o churn, apresenta mais outliers.
# Calculando algumas estatísticas para a variável especificada.
utlex.varStats(col = col, data = dataTrain, target = target)
Destacamos que:
# Definindo o nome da variável a ser analisada.
col = 'total_eve_calls'
# Definindo o nome da variável Target.
target = 'churn'
# Definindo a descrição da variável nos gráficos.
label = 'Ligações totais à Tarde'
# Capturando variáveis especificadas do Dataset.
data = dataTrain[[col, target]]
# Criando uma variável count para contabilizar as ocorrências de cada registro.
data['count'] = 1
# Agrupando dados e contabilizando o número de ocorrências.
data = data.groupby(by = [target, col]).sum()
# Reorganizando DataFrame.
data = data.reset_index()
# Plotando um gráfico de histograma para a variável especificada.
utlex.plotHist (
data = dataTrain[[col, target]],
title = 'Histograma para a variável ' + col,
xaxis = label,
yaxis = 'Frequência Absoluta',
col = col,
target = target,
groups = True
)
Os dois grupos de clientes, aparentam ter uma distribuição normal, para o número de ligações totais à tarde.
# Criando um gráfico de Densidade para a variável especificada.
utlex.plotDensity (
data = dataTrain[[col, target]],
title = 'Gráfico de Densidade para a variável ' + col,
xaxis = label,
col = col,
target = target,
group = True
)
A distribuição de densidade dos grupos é muito semelhante.
# Plotando um gráfico de boxplot para a variável especificada.
utlex.plotBoxplot (
data = dataTrain[[col, target]],
title = 'Boxplot para a variável ' + col,
yaxis = label,
xaxis = target.capitalize(),
col = col,
target = target,
kind = 'groups'
)
O grupo de clientes que não realizaram o churn apresenta mais outliers.
# Calculando algumas estatísticas para a variável especificada.
utlex.varStats(col = col, data = dataTrain, target = target)
Destacamos que:
# Definindo o nome da variável a ser analisada.
col = 'total_eve_charge'
# Definindo o nome da variável Target.
target = 'churn'
# Definindo a descrição da variável nos gráficos.
label = 'Carga total à Tarde'
# Capturando variáveis especificadas do Dataset.
data = dataTrain[[col, target]]
# Criando uma variável count para contabilizar as ocorrências de cada registro.
data['count'] = 1
# Agrupando dados e contabilizando o número de ocorrências.
data = data.groupby(by = [target, col]).sum()
# Reorganizando DataFrame.
data = data.reset_index()
# Plotando um gráfico de histograma para a variável especificada.
utlex.plotHist (
data = dataTrain[[col, target]],
title = 'Histograma para a variável ' + col,
xaxis = label,
yaxis = 'Frequência Absoluta',
col = col,
target = target,
groups = True
)
# Criando um gráfico de Densidade para a variável especificada.
utlex.plotDensity (
data = dataTrain[[col, target]],
title = 'Gráfico de Densidade para a variável ' + col,
xaxis = label,
col = col,
target = target,
group = True
)
A carga total à tarde dos grupos, parece ser normalmente distribuida.
# Plotando um gráfico de boxplot para a variável especificada.
utlex.plotBoxplot (
data = dataTrain[[col, target]],
title = 'Boxplot para a variável ' + col,
yaxis = label,
xaxis = target.capitalize(),
col = col,
target = target,
kind = 'groups'
)
O grupo de clientes que não realizaram o churn, apresenta mais outliers.
# Calculando algumas estatísticas para a variável especificada.
utlex.varStats(col = col, data = dataTrain, target = target)
Destacamos que:
# Definindo o nome da variável a ser analisada.
col = 'total_night_minutes'
# Definindo o nome da variável Target.
target = 'churn'
# Definindo a descrição da variável nos gráficos.
label = 'Total de minutos à Noite'
# Capturando variáveis especificadas do Dataset.
data = dataTrain[[col, target]]
# Criando uma variável count para contabilizar as ocorrências de cada registro.
data['count'] = 1
# Agrupando dados e contabilizando o número de ocorrências.
data = data.groupby(by = [target, col]).sum()
# Reorganizando DataFrame.
data = data.reset_index()
# Plotando um gráfico de histograma para a variável especificada.
utlex.plotHist (
data = dataTrain[[col, target]],
title = 'Histograma para a variável ' + col,
xaxis = label,
yaxis = 'Frequência Absoluta',
col = col,
target = target,
groups = True
)
# Criando um gráfico de Densidade para a variável especificada.
utlex.plotDensity (
data = dataTrain[[col, target]],
title = 'Gráfico de Densidade para a variável ' + col,
xaxis = label,
col = col,
target = target,
group = True
)
O total de minutos à noite para os grupos, tem uma distribuição aproximadamente normal.
# Plotando um gráfico de boxplot para a variável especificada.
utlex.plotBoxplot (
data = dataTrain[[col, target]],
title = 'Boxplot para a variável ' + col,
yaxis = label,
xaxis = target.capitalize(),
col = col,
target = target,
kind = 'groups'
)
O grupo de clientes que não realizaram o churn, apresenta mais outliers.
# Calculando algumas estatísticas para a variável especificada.
utlex.varStats(col = col, data = dataTrain, target = target)
Destacamos que:
# Definindo o nome da variável a ser analisada.
col = 'total_night_calls'
# Definindo o nome da variável Target.
target = 'churn'
# Definindo a descrição da variável nos gráficos.
label = 'Total de chamadas Noturnas'
# Capturando variáveis especificadas do Dataset.
data = dataTrain[[col, target]]
# Criando uma variável count para contabilizar as ocorrências de cada registro.
data['count'] = 1
# Agrupando dados e contabilizando o número de ocorrências.
data = data.groupby(by = [target, col]).sum()
# Reorganizando DataFrame.
data = data.reset_index()
# Plotando um gráfico de histograma para a variável especificada.
utlex.plotHist (
data = dataTrain[[col, target]],
title = 'Histograma para a variável ' + col,
xaxis = label,
yaxis = 'Frequência Absoluta',
col = col,
target = target,
groups = True
)
O total de chamadas noturnas para os grupos, aparenta ser normalmente distribuído.
# Criando um gráfico de Densidade para a variável especificada.
utlex.plotDensity (
data = dataTrain[[col, target]],
title = 'Gráfico de Densidade para a variável ' + col,
xaxis = label,
col = col,
target = target,
group = True
)
# Plotando um gráfico de boxplot para a variável especificada.
utlex.plotBoxplot (
data = dataTrain[[col, target]],
title = 'Boxplot para a variável ' + col,
yaxis = label,
xaxis = target.capitalize(),
col = col,
target = target,
kind = 'groups'
)
O grupo de clientes que não realizaram o churn, apresenta mais outliers.
# Calculando algumas estatísticas para a variável especificada.
utlex.varStats(col = col, data = dataTrain, target = target)
Destacamos que:
# Definindo o nome da variável a ser analisada.
col = 'total_night_charge'
# Definindo o nome da variável Target.
target = 'churn'
# Definindo a descrição da variável nos gráficos.
label = 'Carga noturna Total'
# Capturando variáveis especificadas do Dataset.
data = dataTrain[[col, target]]
# Criando uma variável count para contabilizar as ocorrências de cada registro.
data['count'] = 1
# Agrupando dados e contabilizando o número de ocorrências.
data = data.groupby(by = [target, col]).sum()
# Reorganizando DataFrame.
data = data.reset_index()
# Plotando um gráfico de histograma para a variável especificada.
utlex.plotHist (
data = dataTrain[[col, target]],
title = 'Histograma para a variável ' + col,
xaxis = label,
yaxis = 'Frequência Absoluta',
col = col,
target = target,
groups = True
)
A carga noturna total para os grupos, aparenta ser normalmente distribuída.
# Criando um gráfico de Densidade para a variável especificada.
utlex.plotDensity (
data = dataTrain[[col, target]],
title = 'Gráfico de Densidade para a variável ' + col,
xaxis = label,
col = col,
target = target,
group = True
)
# Plotando um gráfico de boxplot para a variável especificada.
utlex.plotBoxplot (
data = dataTrain[[col, target]],
title = 'Boxplot para a variável ' + col,
yaxis = label,
xaxis = target.capitalize(),
col = col,
target = target,
kind = 'groups'
)
O grupo de clientes que não realizaram o churn, apresenta mais outliers.
# Calculando algumas estatísticas para a variável especificada.
utlex.varStats(col = col, data = dataTrain, target = target)
Destacamos que:
# Definindo o nome da variável a ser analisada.
col = 'total_intl_minutes'
# Definindo o nome da variável Target.
target = 'churn'
# Definindo a descrição da variável nos gráficos.
label = 'Total de minutos Internacionais'
# Capturando variáveis especificadas do Dataset.
data = dataTrain[[col, target]]
# Criando uma variável count para contabilizar as ocorrências de cada registro.
data['count'] = 1
# Agrupando dados e contabilizando o número de ocorrências.
data = data.groupby(by = [target, col]).sum()
# Reorganizando DataFrame.
data = data.reset_index()
# Plotando um gráfico de histograma para a variável especificada.
utlex.plotHist (
data = dataTrain[[col, target]],
title = 'Histograma para a variável ' + col,
xaxis = label,
yaxis = 'Frequência Absoluta',
col = col,
target = target,
groups = True
)
# Criando um gráfico de Densidade para a variável especificada.
utlex.plotDensity (
data = dataTrain[[col, target]],
title = 'Gráfico de Densidade para a variável ' + col,
xaxis = label,
col = col,
target = target,
group = True
)
# Plotando um gráfico de boxplot para a variável especificada.
utlex.plotBoxplot (
data = dataTrain[[col, target]],
title = 'Boxplot para a variável ' + col,
yaxis = label,
xaxis = target.capitalize(),
col = col,
target = target,
kind = 'groups'
)
O grupo de clientes que não realizaram o churn, apresenta mais outliers.
# Calculando algumas estatísticas para a variável especificada.
utlex.varStats(col = col, data = dataTrain, target = target)
Destacamos que:
# Definindo o nome da variável a ser analisada.
col = 'total_intl_calls'
# Definindo o nome da variável Target.
target = 'churn'
# Definindo a descrição da variável nos gráficos.
label = 'Total de chamadas Internacionais'
# Capturando variáveis especificadas do Dataset.
data = dataTrain[[col, target]]
# Criando uma variável count para contabilizar as ocorrências de cada registro.
data['count'] = 1
# Agrupando dados e contabilizando o número de ocorrências.
data = data.groupby(by = [target, col]).sum()
# Reorganizando DataFrame.
data = data.reset_index()
# Plotando um gráfico de barras para a variável especificada.
utlex.plotBar (
data = data,
col = col,
target = target,
title = 'Churn dos clientes por ' + label,
yaxis = 'Frequência Absoluta',
xaxis = label,
kind = 'groups',
orientation = 'h'
)
Os grupos de cliente, possuem uma assimetria à direita.
# Criando um gráfico de Densidade para a variável especificada.
utlex.plotDensity (
data = dataTrain[[col, target]],
title = 'Gráfico de Densidade para a variável ' + col,
xaxis = label,
col = col,
target = target,
group = True
)
# Plotando um gráfico de boxplot para a variável especificada.
utlex.plotBoxplot (
data = dataTrain[[col, target]],
title = 'Boxplot para a variável ' + col,
yaxis = label,
xaxis = target.capitalize(),
col = col,
target = target,
kind = 'groups'
)
O grupo de clientes que não realizaram o churn, apresenta mais outliers.
# Calculando algumas estatísticas para a variável especificada.
utlex.varStats(col = col, data = dataTrain, target = target)
Destacamos que:
# Definindo o nome da variável a ser analisada.
col = 'total_intl_charge'
# Definindo o nome da variável Target.
target = 'churn'
# Definindo a descrição da variável nos gráficos.
label = 'Carga Internacional Total'
# Capturando variáveis especificadas do Dataset.
data = dataTrain[[col, target]]
# Criando uma variável count para contabilizar as ocorrências de cada registro.
data['count'] = 1
# Agrupando dados e contabilizando o número de ocorrências.
data = data.groupby(by = [target, col]).sum()
# Reorganizando DataFrame.
data = data.reset_index()
# Plotando um gráfico de histograma para a variável especificada.
utlex.plotHist (
data = dataTrain[[col, target]],
title = 'Histograma para a variável ' + col,
xaxis = label,
yaxis = 'Frequência Absoluta',
col = col,
target = target,
groups = True
)
# Criando um gráfico de Densidade para a variável especificada.
utlex.plotDensity (
data = dataTrain[[col, target]],
title = 'Gráfico de Densidade para a variável ' + col,
xaxis = label,
col = col,
target = target,
group = True
)
A carga internacional total para os grupos, tem uma distribuição aproximadamente normal.
# Plotando um gráfico de boxplot para a variável especificada.
utlex.plotBoxplot (
data = dataTrain[[col, target]],
title = 'Boxplot para a variável ' + col,
yaxis = label,
xaxis = target.capitalize(),
col = col,
target = target,
kind = 'groups'
)
O grupo de clientes que não realizaram o churn, apresenta mais outliers.
# Calculando algumas estatísticas para a variável especificada.
utlex.varStats(col = col, data = dataTrain, target = target)
Destacamos que:
# Definindo o nome da variável a ser analisada.
col = 'number_customer_service_calls'
# Definindo o nome da variável Target.
target = 'churn'
# Definindo a descrição da variável nos gráficos.
label = 'Número de chamadas de atendimento ao Cliente'
# Capturando variáveis especificadas do Dataset.
data = dataTrain[[col, target]]
# Criando uma variável count para contabilizar as ocorrências de cada registro.
data['count'] = 1
# Agrupando dados e contabilizando o número de ocorrências.
data = data.groupby(by = [target, col]).sum()
# Reorganizando DataFrame.
data = data.reset_index()
# Plotando um gráfico de barras para a variável especificada.
utlex.plotBar (
data = data,
col = col,
target = target,
title = 'Churn dos clientes por ' + label,
yaxis = 'Frequência Absoluta',
xaxis = label,
kind = 'groups',
orientation = 'h'
)
Os grupos possuem uma assimetria à direita.
# Criando um gráfico de Densidade para a variável especificada.
utlex.plotDensity (
data = dataTrain[[col, target]],
title = 'Gráfico de Densidade para a variável ' + col,
xaxis = label,
col = col,
target = target,
group = True
)
O grupo dos clientes que não realizaram o churn, apresentam 4 modas para o número de chamadas de atendimento ao cliente: 1, 2, 3 e 4.
# Plotando um gráfico de boxplot para a variável especificada.
utlex.plotBoxplot (
data = dataTrain[[col, target]],
title = 'Boxplot para a variável ' + col,
yaxis = label,
xaxis = target.capitalize(),
col = col,
target = target,
kind = 'groups'
)
O grupo de clientes que não realizaram o churn, apresenta mais outliers.
# Calculando algumas estatísticas para a variável especificada.
utlex.varStats(col = col, data = dataTrain, target = target)
Destacamos que:
Nesta etapa, desejamos verificar como as variáveis se correlacionam, ou seja, como uma variável ajuda a prever o valor de outra variável no dataset.
# Criando uma matriz de correlação.
corr = dataTrain.corr()
# Selecionando o triângulo superior da matriz de correlação.
upper = corr.abs().where(np.triu(np.ones(corr.shape), k = 1).astype(bool))
# Capturando o nome das variáveis que apresentam uma correlação maior do que 0.95.
to_drop = [column for column in upper.columns if any(upper[column] > 0.95)]
# Exibindo o nome das variáveis altamente correlacionadas.
pd.DataFrame(data = to_drop, columns = ['Highly correlated'])
# Plotando a matriz de correlação entre as variáveis do DataFrame.
utlex.plotCorr(corr)
Detectamos a existência de variáveis altamente correlacionadas, dentre elas, 5 estão perfeitamente correlacionadas e deverão ser eliminadas dos conjuntos de dados.
Observamos que as variáveis total_day_minutes, total_day_charge, number_customer_service_calls e international_plan_dummy são as que apresentam as correlações mais fortes com a variável a ser prevista.
Iremos separar as variáveis preditoras, da variável a ser prevista, dentro do conjunto de dados.
# Eliminando as variáveis altamente correlacionadas dos conjuntos de dados de treino e de teste.
dataTrain = dataTrain.drop(to_drop, axis = 1)
dataTest = dataTest.drop(to_drop, axis = 1)
# Capturando o nome das colunas do tipo categórico presentes no DataFrame.
categ = dataTrain.select_dtypes(['category']).columns
# Capturando as variáveis targets do conjunto de dados de treino e de teste.
trainTarget = dataTrain['churn_dummy']
testTarget = dataTest['churn_dummy']
# Eliminando as variáveis target do conjunto de dados de treino e de teste.
trainFeatures = dataTrain.drop(labels = 'churn_dummy', axis = 1)
testFeatures = dataTest.drop(labels = 'churn_dummy', axis = 1)
# Eliminando as variáveis categóricas do conjunto de dados de treino e de teste.
trainFeatures = trainFeatures.drop(labels = categ, axis = 1)
testFeatures = testFeatures.drop(labels = categ, axis = 1)
# Verificando as novas dimensões do DataFrame de treino.
trainFeatures.shape
# Verificando as novas dimensões do DataFrame de teste.
testFeatures.shape
# Seed para reproduzir o mesmo resultado
seed = 100
# Cria o balanceador SMOTE
smote_bal = SMOTE(random_state = seed)
# Aplica o balanceador
trainFeatures_res, trainTarget_res = smote_bal.fit_resample(trainFeatures, trainTarget)
# Shape dos dados originais
trainFeatures.shape
# Shape dos dados reamostrados
trainFeatures_res.shape
# Shape dos dados reamostrados
trainTarget_res.shape
# Convertendo Serie dados reamostrados variavel target para dataframe.
df = trainTarget_res.to_frame()
# Atribuindo labels diferentes para as categorias da variável target.
df['churn_dummy'] = ['Yes' if v == 1 else 'No' for v in df['churn_dummy']]
# Alterando a variável target para o tipo de dado categórico.
df['churn_dummy'] = df['churn_dummy'].astype('category')
# Definindo o nome da variável a ser analisada.
col = 'churn_dummy'
# Definindo a descrição da variável nos gráficos.
label = 'Churn'
# Contabilizando a frequência absoluta, de cada categoria presente na variável especificada.
dataCounts = df[col].value_counts()
# Plotando um gráfico de barras para a variável especificada.
utlex.plotBar (
data = dataCounts,
title = 'Frequência absoluta das categorias da Feature ' + col + ' após balanceamento de classe',
yaxis = 'Frequência Absoluta',
xaxis = label
)
# Plotando um gráfico de pizza para a variável especificada.
utlex.plotPie (
data = dataCounts,
title = 'Frequência relativa das categorias da feature ' + col + ' após balanceamento de classe'
)
Agora que nossa variável target esta balanceada podemos seguir com a divisão dos dados em treino e teste e a seleção das melhores variáveis para a modelagem preditiva.
# Criando um objeto da classe MinMaxScaler().
scaler = MinMaxScaler()
# Aplicando a escala nas Features e capturando o resultado obtido.
trainFeaturesMM = scaler.fit_transform(trainFeatures)
# Criando um DataFrame com os resultados obtidos.
trainFeaturesMM = pd.DataFrame(data = trainFeaturesMM, columns = trainFeatures.columns)
# Criando um objeto da classe StandardScaler().
scaler = StandardScaler()
# Aplicando a escala nas Features e capturando o resultado obtido.
trainFeaturesStandScaler = scaler.fit_transform(trainFeatures)
# Criando um DataFrame com os resultados obtidos.
trainFeaturesStandScaler = pd.DataFrame(data = trainFeaturesStandScaler, columns = trainFeatures.columns)
# Criando um objeto da classe StandardScaler().
scaler = PowerTransformer(method = 'yeo-johnson', standardize = False)
# Aplicando a escala nas Features e capturando o resultado obtido.
trainFeaturesNormDistribuition = scaler.fit_transform(trainFeaturesStandScaler)
# Criando um DataFrame com os resultados obtidos.
trainFeaturesNormDistribuition = pd.DataFrame(data = trainFeaturesNormDistribuition, columns = trainFeatures.columns)
# Normalizando cada feature para uma unidade uniforme (vetor unitário).
trainFeaturesNormalized = normalize(trainFeatures, axis = 1)
# Criando um DataFrame com os resultados obtidos.
trainFeaturesNormalized = pd.DataFrame(data = trainFeaturesNormalized, columns = trainFeatures.columns)
Aplicaremos diferentes técnicas de Feature Selection, para determinar qual é a melhor combinação de variáveis preditoras a ser utilizada.
Este método seleciona recursos de acordo com as k pontuações mais altas.
# Definindo qual conjunto de dados, já escalado, deve ser utilizado.
tFeatures = trainFeaturesMM
# Instanciando um objeto da classe SelectKBest, para selecionar as melhores variáveis preditoras.
skb = SelectKBest(chi2, k = 9)
# Capturando os scores das variáveis preditoras.
bestFeatuesSKB = skb.fit_transform(tFeatures, trainTarget)
# Capturando o nome das variáveis preditoras.
bfSkb = tFeatures.columns[skb.get_support()]
# Exibindo o nome das variáveis preditoras.
bfSkb
# Criando um DataFrame com os scores obtidos para cada uma das Features segundo a técnica utilizada.
sc = pd.DataFrame(skb.scores_, index = tFeatures.columns, columns = ['score'])
# Capturando os scores das melhores variáveis preditoras.
sc = sc[skb.get_support()]
# Ordenando o Dataframe com os scores.
sc = sc.sort_values(by = 'score', ascending = False)
# Plotando um gráfico de barras, dos scores gerados para as features, a partir da técnica utilizada.
utlex.plotBar (
data = sc.score,
title = 'Scores das melhores features com o SelectKBest',
yaxis = 'Features',
xaxis = 'Scores',
orientation = 'h'
)
O Information gain ou Mutual information mede quanta informação a presença / ausência de um recurso contribui para fazer a previsão correta da variável target.
# Definindo qual conjunto de dados, já escalado, deve ser utilizado.
tFeatures = trainFeaturesMM
# Instanciando um objeto da classe mutual_info_classif.
bestFeatuesIG = mutual_info_classif(tFeatures, trainTarget, discrete_features = 'auto', n_neighbors = 3)
# Inserindo Scores obtidos em um DataFrame.
scoreFeatures = pd.DataFrame(bestFeatuesIG, index = tFeatures.columns, columns = ['score'])
# Capturando as 5 variáveis com os maiores scores.
bfIg = scoreFeatures.sort_values(by='score', ascending=False).head(9)
# Plotando um gráfico de barras, dos scores gerados para as features, a partir da técnica utilizada.
utlex.plotBar (
data = bfIg.score,
title = 'Scores das melhores features com o Information Gain',
yaxis = 'Features',
xaxis = 'Scores',
orientation = 'h'
)
# Capturando o nome das variáveis preditoras.
bfIg = bfIg.index
# Exibindo o nome das variáveis preditoras.
bfIg
Se os recursos forem categóricos, calcularemos uma estatística qui-quadrado entre cada recurso e a variável target. No entanto, se os recursos forem quantitativos, calcularemos a ANOVA F-Value entre cada recurso e a variável target.
As pontuações do F-Value examinam se, quando agrupamos a característica numérica pela variável target, as médias para cada grupo se tornam significativamente diferentes.
# Definindo qual conjunto de dados, já escalado, deve ser utilizado.
tFeatures = trainFeaturesMM
# Instanciando um objeto da classe SelectKBest para selecionar as 5 melhores variáveis preditoras a partir
# do scores ANOVA F-Values.
skb = SelectKBest(f_classif, k = 9)
# Capturando as melhores variáveis preditoras.
bestFeatuesANOVA = skb.fit_transform(tFeatures, trainTarget)
# Capturando o nome das melhores variáveis preditoras.
bfAnova = tFeatures.columns[skb.get_support()]
# Exibindo o nome das melhores variáveis preditoras.
bfAnova
# Criando um DataFrame com os scores obtidos para cada uma das Features segundo a técnica utilizada.
sc = pd.DataFrame(skb.scores_, index = tFeatures.columns, columns = ['score'])
# Capturando os scores das melhores variáveis preditoras.
sc = sc[skb.get_support()]
# Ordenando o Dataframe com os scores.
sc = sc.sort_values(by = 'score', ascending = False)
# Plotando um gráfico de barras, dos scores gerados para as features, a partir da técnica utilizada.
utlex.plotBar (
data = sc.score,
title = 'Scores das melhores features com o ANOVA F-value',
yaxis = 'Features',
xaxis = 'Scores',
orientation = 'h'
)
O Forward Selection é um método iterativo, no qual começamos sem ter nenhum recurso no modelo. A cada iteração, adicionamos uma variável que melhora o modelo e efetuamos este procedimento até que a performance do modelo pare de evoluir.
A seleção de recursos começa avaliando todas as variáveis individualmente, e seleciona aquela que gera o algoritmo com o melhor desempenho, de acordo com um critério de avaliação predefinido. Em seguida, se avalia todas as combinações possíveis das variáveis já selecionadas e dos recursos ainda não escolhidos para definir a combinação que produz o algoritmo com a melhor performance, com base nos mesmos critérios predefinidos.
# Definindo qual conjunto de dados, já escalado, deve ser utilizado.
tFeatures = trainFeaturesMM
# Instanciando um objeto da classe SFS para selecionar as melhores variáveis preditoras segundo sua acurácia,
# utilizando o algoritmo XGBClassifer.
sfs = SFS (
estimator = xgb.XGBClassifier(use_label_encoder=False,eval_metric='mlogloss'),
k_features = 9,
forward = True,
floating = False,
verbose = 2,
scoring = 'accuracy',
cv = 3
)
# Capturando as variáveis preditoras.
sfs = sfs.fit(
X = tFeatures,
y = trainTarget
)
# Capturando o nome das variáveis preditoras.
bfSfs = tFeatures.columns[list(sfs.k_feature_idx_)]
# Exibindo o nome das variáveis preditoras.
bfSfs
# Capturando os resultados obtidos pela Técnica Forward Selection.
sc = pd.DataFrame(sfs.get_metric_dict())
# Capturando os scores e o nome das Features, gerados a cada busca.
sc = sc.loc[['cv_scores', 'feature_names'], :].transpose()
# Capturando o nome das features utilizadas em cada avaliação.
featureNames = sc.feature_names
# Criando índices com o número de Features utilizadas em cada avaliação.
columns = [str(i) + ' Feature' if i == 1 else str(i) + ' Features' for i in range(1, sc.shape[0] + 1)]
# Remodelando os dados do DataFrame para serem plotados.
fs = pd.DataFrame()
for i in range(1, sc.shape[0] + 1):
# Atribui os primeiros scores ao DataFrame, caso esteja vazio.
if sc.empty:
fs = pd.DataFrame(sc['cv_scores'][i], columns = [columns[i - 1]])
else:
fs[columns[i - 1]] = sc['cv_scores'][i]
# Plotando os scores da acurácia, obtida pelas features selecionadas em cada fase de busca, segundo a técnica Forward Selection.
utlex.plotBoxplot (
data = fs,
title = 'Acurácia das melhores Features encontradas pelo técnica Forward Selection',
xaxis = 'Features selecionadas'
)
# Transpondo a Série Temporal.
fs = fs.transpose()
# Criando uma nova coluna, com os nomes das Features utilizadas, em cada avaliação no DataFrame.
fs['featuresNames'] = [', '.join(f) for f in featureNames]
# Exibindo o nome das features utilizadas em cada avaliação.
fs[['featuresNames']]
O Extremely Randomized Trees Classifier (Extra Trees Classifier) é um tipo de técnica de aprendizagem de conjunto que agrega os resultados de várias árvores de decisão descorrelacionadas coletadas em uma “floresta” para produzir seu resultado de classificação. Em conceito, é muito semelhante a um Classificador Random Forest e só difere na forma de construção das árvores de decisão na floresta.
Cada árvore de decisão na floresta de árvores extras é construída a partir da amostra de treinamento original. Então, em cada nó de teste, cada árvore é fornecida com uma amostra aleatória de k recursos do conjunto de recursos a partir do qual cada árvore de decisão deve selecionar o melhor recurso para dividir os dados com base em alguns critérios matemáticos (normalmente o índice de Gini). Essa amostra aleatória de recursos leva à criação de várias árvores de decisão não correlacionadas.
Para realizar a seleção de características usando a estrutura de floresta acima, durante a construção da floresta, para cada característica, a redução total normalizada nos critérios matemáticos usados na decisão da característica de divisão (Índice de Gini se o Índice de Gini for usado na construção de floresta) é computado. Esse valor é chamado de Importância Gini do recurso. Para realizar a seleção de recursos, cada recurso é ordenado em ordem decrescente de acordo com a Importância Gini de cada recurso e o usuário seleciona os k principais recursos de acordo com sua escolha.
# Definindo qual conjunto de dados, já escalado, deve ser utilizado.
tFeatures = trainFeaturesMM
# Instanciando um objeto da classe ExtraTreesClassifier.
modelETC = ExtraTreesClassifier()
# Computando os scores de cada feature.
modelETC.fit (
X = tFeatures,
y = trainTarget
)
# Inserindo Scores obtidos em uma Série Temporal.
featuresImpETC = pd.DataFrame(data = modelETC.feature_importances_, index = tFeatures.columns, columns = ['score'])
# Ordenando o nome das variáveis preditoras segundo seu score em ordem decrescente.
bfEtc = featuresImpETC.sort_values(by = 'score', ascending = False).head(9)
# Plotando um gráfico de barras, dos scores gerados para as features, a partir da técnica utilizada.
utlex.plotBar (
data = bfEtc.score,
title = 'Scores das melhores features com o Extra Trees Classifier',
yaxis = 'Features',
xaxis = 'Scores',
orientation = 'h'
)
# Capturando o nome das variáveis preditoras.
bfEtc = bfEtc.index
# Exibindo o nome das variáveis preditoras.
bfEtc
O Random Forest, é um dos algoritmos de aprendizado de máquina mais populares. É um dos mais bem-sucedidos porque fornece, em geral, um bom desempenho preditivo, baixo overfitting e é de fácil interpretabilidade.
Essa interpretabilidade é dada pela facilidade de se derivar a importância de cada variável na árvore de decisão. Em outras palavras, é fácil calcular o quanto cada variável está contribuindo para a decisão do modelo.
O Random Forest consiste em 4-12 centenas de árvores de decisão, cada uma delas construída sobre uma extração aleatória das observações do conjunto de dados e uma extração aleatória das características. Nem toda árvore vê todas as características ou todas as observações, e isso garante que as árvores sejam descorrelacionadas e, portanto, menos sujeitas a sobreajuste. Cada árvore também é uma sequência de perguntas sim-não com base em um único recurso ou em uma combinação de recursos. Em cada nó (isto é em cada questão), os três dividem o conjunto de dados em 2 depósitos, cada um deles hospedando observações que são mais semelhantes entre si e diferentes das do outro bloco. Portanto, a importância de cada recurso é derivada do quão "puro" cada um dos blocos é.
Para classificação, a medida de impureza é a impureza de Gini ou o ganho / entropia de informação. Para regressão, a medida de impureza é a variância. Portanto, ao treinar uma árvore, é possível calcular o quanto cada recurso diminui a impureza. Quanto maior for a diminuição da impureza que um recurso gerar, mais importante ele será. Em florestas aleatórias, a diminuição da impureza de cada recurso pode ser calculada em média entre as árvores para determinar a importância final da variável.
# Definindo qual conjunto de dados, já escalado, deve ser utilizado.
tFeatures = trainFeaturesMM
# Instanciando um objeto da classe RandomForestClassifier.
rfImp = RandomForestClassifier (
n_estimators = 200,
random_state = 0
)
# Treinando o classificador com o conjunto de dados de treino.
rfImp.fit(
X = tFeatures,
y = trainTarget
)
# Prevendo os scores das features dos dados de treino.
pred = rfImp.predict(tFeatures)
# Convertendo os scores para um DataFrame.
featuresImpRf = pd.Series(data = rfImp.feature_importances_, index = tFeatures.columns)
# Capturando os scores de cada uma das features.
bfRf = featuresImpRf.nlargest(9)
# Plotando um gráfico de barras, dos scores gerados para as features, a partir da técnica utilizada.
utlex.plotBar (
data = bfRf,
title = 'Scores das melhores features com o Random Forest',
yaxis = 'Features',
xaxis = 'Scores',
orientation = 'h'
)
# Capturando o nome das variáveis preditoras.
bfRf = bfRf.index
# Exibindo o nome das variáveis preditoras.
bfRf
A Análise de componente principal (Principal Component Analysis - PCA) é uma técnica de redução de dimensionalidade linear que pode ser utilizada para extrair informações de um espaço de alta dimensão projetando-as em um subespaço de dimensão inferior. Ele tenta preservar as partes essenciais que têm mais variação dos dados e remover as partes não essenciais com menos variação. As dimensões nada mais são do que recursos que representam os dados.
Uma coisa importante a se notar sobre o PCA é que é uma técnica de redução de dimensionalidade não supervisionada. Você pode agrupar os pontos de dados semelhantes com base na correlação de recursos entre eles sem qualquer supervisão (ou rótulos).
# Aplicando a técnica PCA, para criar 10 Componentes, a partir dos dados de treino e de teste.
trainFeaturesPCA, testFeaturesPCA = utlpca.pcaTransform(train = trainFeatures, test = testFeatures)
RFE é um algoritmo de seleção de recurso do tipo wrapper. Isso significa que um algoritmo de aprendizado de máquina diferente é fornecido e usado no núcleo do método, é empacotado pelo RFE e usado para ajudar a selecionar recursos. Isso contrasta com as seleções de recursos com base em filtro que pontuam cada recurso e selecionam os recursos com a maior (ou menor) pontuação.
Tecnicamente, o RFE é um algoritmo de seleção de recursos no estilo wrapper que também usa a seleção de recursos com base em filtro internamente.
O RFE funciona procurando por um subconjunto de recursos começando com todos os recursos no conjunto de dados de treinamento e removendo com sucesso os recursos até que o número desejado permaneça.
Isso é obtido ajustando-se o algoritmo de aprendizado de máquina usado no núcleo do modelo, classificando os recursos por importância, descartando os recursos menos importantes e reajustando o modelo. Este processo é repetido até que um determinado número de recursos permaneça.
Os recursos são pontuados usando o modelo de aprendizado de máquina fornecido ou usando um método estatístico.
# Definindo qual conjunto de dados, já escalado, deve ser utilizado.
tFeatures = trainFeaturesMM
# Instanciando um objeto da classe RFE para selecionar as melhores variáveis preditoras, utilizando o algoritmo XGBClassifer.
rfe = RFE (
estimator = xgb.XGBClassifier(use_label_encoder=False,eval_metric='mlogloss'),
n_features_to_select = 9
)
# Capturando as melhores variáveis preditoras.
rfeFit = rfe.fit (
X = tFeatures,
y = trainTarget
)
# Capturando o nome das variáveis preditoras.
bfRfe = tFeatures.columns[rfeFit.support_]
# Exibindo o nome das variáveis preditoras.
bfRfe
# Criando uma lista, com todos os resultados gerados pelas técnicas de Feature Selection utilizadas.
bestFeaturesNames = [bfSkb.values, bfIg.values, bfAnova.values, bfSfs.values, bfEtc.values, bfRf.values, bfRfe.values]
# Convertendo a lista, para um DataFrame, com as features organizadas em ordem alfabética.
bestFeaturesNamesOrdered = pd.DataFrame (
data = [sorted(r) for r in bestFeaturesNames],
index = ['skb', 'ig', 'anova', 'sfs', 'etc', 'rf', 'rfe'],
columns = ['Feature' + str(i) for i in range(1, bestFeaturesNames[1].shape[0] + 1)]
)
# Convertendo a lista para um DataFrame.
bestFeaturesNames = pd.DataFrame (
data = bestFeaturesNames,
index = ['skb', 'ig', 'anova', 'sfs', 'etc', 'rf', 'rfe'],
columns = ['Importance_' + str(i) for i in range(1, bestFeaturesNames[1].shape[0] + 1)]
)
# Exibindo DataFrame, com as features ordenadas segundo seu nível de importância.
bestFeaturesNames
# Contabilizando o número de ocorrências de cada uma das features dentro do DataFrame.
bestFeaturesNames.melt().value.value_counts()
# Salvando o DataFrame, com as melhores variáveis selecionadas, pelas técnicas de Feature Selection utilizadas.
bestFeaturesNames.to_csv('outputs/bestFeaturesNames.csv')
Iremos criar modelos preditivos, com diferentes algoritmos, e com as Features em diferentes escalas. Também criaremos classificadores utilizando a técnica PCA. Por fim, selecionaremos os modelos que obtiveram as maiores acurácias.
# Treinando classificadores, a partir dos componentes criados pela técnica PCA.
resultsPCA = utlml.classifiersTraining (
features = trainFeaturesPCA,
tTarget = trainTarget
)
# Plotando os scores, da acurácia dos classificadores treinados, em boxplots.
utlex.plotBoxplot(data = resultsPCA[0])
O algoritmo XGBoost, foi o que obteve a melhor acurácia, para o conjunto de componentes do PCA.
# Carregando o DataFrame, com as variáveis selecionadas, por cada uma das técnicas de Feature Selection.
bestFeaturesNames = pd.read_csv('outputs/bestFeaturesNames.csv', index_col = 0)
# Treinando classificadores, a partir da escala, e da técnica de Feature Selection utilizada.
resultsMMSkb = utlml.classifiersTraining (
features = trainFeaturesMM[list(bestFeaturesNames.loc['skb'])],
tTarget = trainTarget
)
# Plotando os scores, da acurácia dos classificadores treinados, em boxplots.
utlex.plotBoxplot(data = resultsMMSkb[0])
# Treinando classificadores, a partir da escala, e da técnica de Feature Selection utilizada.
resultsMMIg = utlml.classifiersTraining (
features = trainFeaturesMM[list(bestFeaturesNames.loc['ig'])],
tTarget = trainTarget
)
# Plotando os scores, da acurácia dos classificadores treinados, em boxplots.
utlex.plotBoxplot(data = resultsMMIg[0])
# Treinando classificadores, a partir da escala, e da técnica de Feature Selection utilizada.
resultsMMAnova = utlml.classifiersTraining (
features = trainFeaturesMM[list(bestFeaturesNames.loc['anova'])],
tTarget = trainTarget
)
# Plotando os scores, da acurácia dos classificadores treinados, em boxplots.
utlex.plotBoxplot(data = resultsMMAnova[0])
# Treinando classificadores, a partir da escala, e da técnica de Feature Selection utilizada.
resultsMMSfs = utlml.classifiersTraining (
features = trainFeaturesMM[list(bestFeaturesNames.loc['sfs'])],
tTarget = trainTarget
)
# Plotando os scores, da acurácia dos classificadores treinados, em boxplots.
utlex.plotBoxplot(data = resultsMMSfs[0])
# Treinando classificadores, a partir da escala, e da técnica de Feature Selection utilizada.
resultsMMEtc = utlml.classifiersTraining (
features = trainFeaturesMM[list(bestFeaturesNames.loc['etc'])],
tTarget = trainTarget
)
# Plotando os scores, da acurácia dos classificadores treinados, em boxplots.
utlex.plotBoxplot(data = resultsMMEtc[0])
# Treinando classificadores, a partir da escala, e da técnica de Feature Selection utilizada.
resultsMMRfe = utlml.classifiersTraining (
features = trainFeaturesMM[list(bestFeaturesNames.loc['rfe'])],
tTarget = trainTarget
)
# Plotando os scores, da acurácia dos classificadores treinados, em boxplots.
utlex.plotBoxplot(data = resultsMMRfe[0])
# Criando uma lista, com todos os resultados considerando os dados transformados pelo algoritmo MinMaxScaler.
bestResultsMM = [pd.DataFrame(resultsPCA[1])['mean'].values,
pd.DataFrame(resultsMMSkb[1])['mean'].values,
pd.DataFrame(resultsMMIg[1])['mean'].values,
pd.DataFrame(resultsMMAnova[1])['mean'].values,
pd.DataFrame(resultsMMSfs[1])['mean'].values,
pd.DataFrame(resultsMMEtc[1])['mean'].values,
pd.DataFrame(resultsMMRfe[1])['mean'].values]
# Convertendo a lista, para um DataFrame, com os resultados organizados.
bestResultsMM = pd.DataFrame (
data = [ sorted(a) for a in bestResultsMM],
index = ['resultsPCA' ,'resultsMMSkb','resultsMMIg','resultsMMAnova','resultsMMSfs','resultsMMEtc','resultsMMRfe'],
columns = [ str(i) for i in pd.DataFrame(resultsPCA[0]).columns]#'LR', 'LDA', 'KNN', 'CART', 'RF', 'XGBoost']
)
# Exibindo DataFrame, com os resultados considerando os dados transformados pelo algoritmo MinMaxScaler..
bestResultsMM.sort_values(by = 'XGBoost', ascending = False)
Os algoritmos RandomForest e XGBoost, foram os que obteveram a melhor acurácia, para o conjunto dados transformados pelo algoritmo MinMaxScaler, em praticamente todos os grupos de Features gerados.
# Treinando classificadores, a partir da escala, e da técnica de Feature Selection utilizada.
resultsSSSkb = utlml.classifiersTraining (
features = trainFeaturesStandScaler[list(bestFeaturesNames.loc['skb'])],
tTarget = trainTarget
)
# Plotando os scores, da acurácia dos classificadores treinados, em boxplots.
utlex.plotBoxplot(data = resultsSSSkb[0])
# Treinando classificadores, a partir da escala, e da técnica de Feature Selection utilizada.
resultsSSIg = utlml.classifiersTraining (
features = trainFeaturesStandScaler[list(bestFeaturesNames.loc['ig'])],
tTarget = trainTarget
)
# Plotando os scores, da acurácia dos classificadores treinados, em boxplots.
utlex.plotBoxplot(data = resultsSSIg[0])
# Treinando classificadores, a partir da escala, e da técnica de Feature Selection utilizada.
resultsSSAnova = utlml.classifiersTraining (
features = trainFeaturesStandScaler[list(bestFeaturesNames.loc['anova'])],
tTarget = trainTarget
)
# Plotando os scores, da acurácia dos classificadores treinados, em boxplots.
utlex.plotBoxplot(data = resultsSSAnova[0])
# Treinando classificadores, a partir da escala, e da técnica de Feature Selection utilizada.
resultsSSSfs = utlml.classifiersTraining (
features = trainFeaturesStandScaler[list(bestFeaturesNames.loc['sfs'])],
tTarget = trainTarget
)
# Plotando os scores, da acurácia dos classificadores treinados, em boxplots.
utlex.plotBoxplot(data = resultsSSSfs[0])
# Treinando classificadores, a partir da escala, e da técnica de Feature Selection utilizada.
resultsSSEtc = utlml.classifiersTraining (
features = trainFeaturesStandScaler[list(bestFeaturesNames.loc['etc'])],
tTarget = trainTarget
)
# Plotando os scores, da acurácia dos classificadores treinados, em boxplots.
utlex.plotBoxplot(data = resultsSSEtc[0])
# Treinando classificadores, a partir da escala, e da técnica de Feature Selection utilizada.
resultsSSRfe = utlml.classifiersTraining (
features = trainFeaturesStandScaler[list(bestFeaturesNames.loc['rfe'])],
tTarget = trainTarget
)
# Plotando os scores, da acurácia dos classificadores treinados, em boxplots.
utlex.plotBoxplot(data = resultsSSRfe[0])
# Criando uma lista, com todos os resultados considerando os dados transformados pelo algoritmo StandardScaler.
bestResultsSS = [pd.DataFrame(resultsSSSkb[1])['mean'].values,
pd.DataFrame(resultsSSIg[1])['mean'].values,
pd.DataFrame(resultsSSAnova[1])['mean'].values,
pd.DataFrame(resultsSSSfs[1])['mean'].values,
pd.DataFrame(resultsSSEtc[1])['mean'].values,
pd.DataFrame(resultsSSRfe[1])['mean'].values]
# Convertendo a lista, para um DataFrame, com os resultados organizados.
bestResultsSS = pd.DataFrame (
data = [ sorted(a) for a in bestResultsSS],
index = ['resultsSSSkb','resultsSSIg','resultsSSAnova','resultsSSSfs','resultsSSEtc','resultsSSRfe'],
columns = [ str(i) for i in pd.DataFrame(resultsSSSkb[0]).columns]
)
# Exibindo DataFrame, com os resultados considerando os dados transformados pelo algoritmo StandardScaler..
bestResultsSS.sort_values(by = 'XGBoost', ascending = False)
Os algoritmos RandomForest e XGBoost, foram os que obteveram a melhor acurácia, para o conjunto dados transformados pelo algoritmo StandardScaler, em praticamente todos os grupos de Features gerados.
# Treinando classificadores, a partir da escala, e da técnica de Feature Selection utilizada.
resultsNDSkb = utlml.classifiersTraining (
features = trainFeaturesNormDistribuition[list(bestFeaturesNames.loc['skb'])],
tTarget = trainTarget
)
# Plotando os scores, da acurácia dos classificadores treinados, em boxplots.
utlex.plotBoxplot(data = resultsNDSkb[0])
# Treinando classificadores, a partir da escala, e da técnica de Feature Selection utilizada.
resultsNDIg = utlml.classifiersTraining (
features = trainFeaturesNormDistribuition[list(bestFeaturesNames.loc['ig'])],
tTarget = trainTarget
)
# Plotando os scores, da acurácia dos classificadores treinados, em boxplots.
utlex.plotBoxplot(data = resultsNDIg[0])
# Treinando classificadores, a partir da escala, e da técnica de Feature Selection utilizada.
resultsNDAnova = utlml.classifiersTraining (
features = trainFeaturesNormDistribuition[list(bestFeaturesNames.loc['anova'])],
tTarget = trainTarget
)
# Plotando os scores, da acurácia dos classificadores treinados, em boxplots.
utlex.plotBoxplot(data = resultsNDAnova[0])
# Treinando classificadores, a partir da escala, e da técnica de Feature Selection utilizada.
resultsNDSfs = utlml.classifiersTraining (
features = trainFeaturesNormDistribuition[list(bestFeaturesNames.loc['sfs'])],
tTarget = trainTarget
)
# Plotando os scores, da acurácia dos classificadores treinados, em boxplots.
utlex.plotBoxplot(data = resultsNDSfs[0])
# Treinando classificadores, a partir da escala, e da técnica de Feature Selection utilizada.
resultsNDEtc = utlml.classifiersTraining (
features = trainFeaturesNormDistribuition[list(bestFeaturesNames.loc['etc'])],
tTarget = trainTarget
)
# Plotando os scores, da acurácia dos classificadores treinados, em boxplots.
utlex.plotBoxplot(data = resultsNDEtc[0])
# Treinando classificadores, a partir da escala, e da técnica de Feature Selection utilizada.
resultsNDRfe = utlml.classifiersTraining (
features = trainFeaturesNormDistribuition[list(bestFeaturesNames.loc['rfe'])],
tTarget = trainTarget
)
# Plotando os scores, da acurácia dos classificadores treinados, em boxplots.
utlex.plotBoxplot(data = resultsNDRfe[0])
# Criando uma lista, com todos os resultados considerando os dados transformados pelo algoritmo Box-Cox.
bestResultsND = [pd.DataFrame(resultsNDSkb[1])['mean'].values,
pd.DataFrame(resultsNDIg[1])['mean'].values,
pd.DataFrame(resultsNDAnova[1])['mean'].values,
pd.DataFrame(resultsNDSfs[1])['mean'].values,
pd.DataFrame(resultsNDEtc[1])['mean'].values,
pd.DataFrame(resultsNDRfe[1])['mean'].values]
# Convertendo a lista, para um DataFrame, com os resultados organizados.
bestResultsND = pd.DataFrame (
data = [ sorted(a) for a in bestResultsND],
index = ['resultsNDSkb','resultsNDIg','resultsNDAnova','resultsNDSfs','resultsNDEtc','resultsNDRfe'],
columns = [ str(i) for i in pd.DataFrame(resultsNDSkb[0]).columns]
)
# Exibindo DataFrame, com os resultados considerando os dados transformados pelo algoritmo Box-Cox.
bestResultsND.sort_values(by = 'XGBoost', ascending = False)
Os algoritmos RandomForest e XGBoost, foram os que obteveram a melhor acurácia, para o conjunto dados transformados pelo algoritmo Box-Cox, em praticamente todos os grupos de Features gerados.
# Treinando classificadores, a partir da escala, e da técnica de Feature Selection utilizada.
resultsNSkb = utlml.classifiersTraining (
features = trainFeaturesNormalized[list(bestFeaturesNames.loc['skb'])],
tTarget = trainTarget
)
# Plotando os scores, da acurácia dos classificadores treinados, em boxplots.
utlex.plotBoxplot(data = resultsNSkb[0])
# Treinando classificadores, a partir da escala, e da técnica de Feature Selection utilizada.
resultsNIg = utlml.classifiersTraining (
features = trainFeaturesNormalized[list(bestFeaturesNames.loc['ig'])],
tTarget = trainTarget
)
# Plotando os scores, da acurácia dos classificadores treinados, em boxplots.
utlex.plotBoxplot(data = resultsNIg[0])
# Treinando classificadores, a partir da escala, e da técnica de Feature Selection utilizada.
resultsNAnova = utlml.classifiersTraining (
features = trainFeaturesNormalized[list(bestFeaturesNames.loc['anova'])],
tTarget = trainTarget
)
# Plotando os scores, da acurácia dos classificadores treinados, em boxplots.
utlex.plotBoxplot(data = resultsNAnova[0])
# Treinando classificadores, a partir da escala, e da técnica de Feature Selection utilizada.
resultsNSfs = utlml.classifiersTraining (
features = trainFeaturesNormalized[list(bestFeaturesNames.loc['sfs'])],
tTarget = trainTarget
)
# Plotando os scores, da acurácia dos classificadores treinados, em boxplots.
utlex.plotBoxplot(data = resultsNSfs[0])
# Treinando classificadores, a partir da escala, e da técnica de Feature Selection utilizada.
resultsNEtc = utlml.classifiersTraining (
features = trainFeaturesNormalized[list(bestFeaturesNames.loc['etc'])],
tTarget = trainTarget
)
# Plotando os scores, da acurácia dos classificadores treinados, em boxplots.
utlex.plotBoxplot(data = resultsNEtc[0])
# Treinando classificadores, a partir da escala, e da técnica de Feature Selection utilizada.
resultsNRfe = utlml.classifiersTraining (
features = trainFeaturesNormalized[list(bestFeaturesNames.loc['rfe'])],
tTarget = trainTarget
)
# Plotando os scores, da acurácia dos classificadores treinados, em boxplots.
utlex.plotBoxplot(data = resultsNRfe[0])
# Criando uma lista, com todos os resultados considerando os dados transformados pelo algoritmo normalize.
bestResultsN = [pd.DataFrame(resultsNSkb[1])['mean'].values,
pd.DataFrame(resultsNIg[1])['mean'].values,
pd.DataFrame(resultsNAnova[1])['mean'].values,
pd.DataFrame(resultsNSfs[1])['mean'].values,
pd.DataFrame(resultsNEtc[1])['mean'].values,
pd.DataFrame(resultsNRfe[1])['mean'].values]
# Convertendo a lista, para um DataFrame, com os resultados organizados.
bestResultsN = pd.DataFrame (
data = [ sorted(a) for a in bestResultsN],
index = ['resultsNRSkb','resultsNIg','resultsNAnova','resultsNSfs','resultsNEtc','resultsNRfe'],
columns = [ str(i) for i in pd.DataFrame(resultsNSkb[0]).columns]
)
# Exibindo DataFrame, com os resultados considerando os dados transformados pelo algoritmo normalize.
bestResultsN.sort_values(by = 'XGBoost', ascending = False)
Os algoritmos RandomForest e XGBoost, foram os que obteveram a melhor acurácia, para o conjunto dados transformados pelo algoritmo normalize, em praticamente todos os grupos de Features gerados.
bestResultsMM.iloc[:,4:6].sort_values(by = 'XGBoost', ascending = False)
bestResultsSS.iloc[:,4:6].sort_values(by = 'XGBoost', ascending = False)
bestResultsND.iloc[:,4:6].sort_values(by = 'XGBoost', ascending = False)
bestResultsN.iloc[:,4:6].sort_values(by = 'XGBoost', ascending = False)
Após as analises preliminares, observamos que as features selecionadas pelo algoritmo Sfs foram as que obtiveram a melhor performance. E por isso, iremos utilizá-las nas fases a seguir..
# Listando as siglas, das técnicas de Feature Selection utilizadas.
bestFeaturesNames.index
# Definindo qual resultado, das técnicas de Feature Selection, deve ser utilizado.
f = list(bestFeaturesNames.loc['sfs'])
Nesta etapa, iremos aplicar diferentes transformações, nas variáveis preditoras dos conjuntos de dados de treino e de teste.
# Aplicando a transformação MinMaxScaler, as Features do conjunto de dados de treino e de teste.
trainFeaturesMM, testFeaturesMM = utlst.dataTransform (
train = trainFeatures[f],
test = testFeatures[f],
transform = 'MM'
)
# Aplicando a transformação StandardScaler, as Features do conjunto de dados de treino e de teste.
trainFeaturesSS, testFeaturesSS = utlst.dataTransform (
train = trainFeatures[f],
test = testFeatures[f],
transform = 'SS'
)
# Aplicando a transformação Yeo-Johnson, as Features do conjunto de dados de treino e de teste.
trainFeaturesNormDistribuition, testFeaturesNormDistribuition = utlst.dataTransform (
train = trainFeatures[f],
test = testFeatures[f],
transform = 'ND'
)
# Aplicando a transformação Normalize, as Features do conjunto de dados de treino e de teste.
trainFeaturesNormalized, testFeaturesNormalized = utlst.dataTransform (
train = trainFeatures[f],
test = testFeatures[f],
transform = 'N'
)
Iremos buscar pelos melhores parâmetros, para criar um modelo com o algoritmo de Random Forest.
# Definindo qual conjunto de dados de treino, já escalado, deve ser utilizado e a sua variável target.
trainX = trainFeaturesSS[f]
trainY = trainTarget
# Definindo qual conjunto de dados de teste, já escalado, deve ser utilizado e a sua variável target.
testX = testFeaturesSS[f]
testY = testTarget
# Definindo os valores que devem ser testados, em cada um dos parâmetros do modelo especificado.
paramGrid = dict (
n_estimators = list(range(100, 301, 25)),
max_depth = [16, 17, 18]
)
# Criando uma instância da classe do modelo Random Forest.
model = RandomForestClassifier()
# Criando o grid, para fazer a busca dos melhores parâmetros para o modelo.
grid = GridSearchCV(estimator = model, param_grid = paramGrid, cv = 10, verbose = True, n_jobs = -1)
# Buscando pelos melhores parâmetros para o modelo.
grid.fit(trainX, trainY)
# Exibindo a configuração, do melhor modelo treinado.
print("\n" + "Melhores Parâmetros para o Modelo:" + "\n\n", grid.best_estimator_)
# Criando o modelo, com a melhor configuração encontrada.
classifierRF = grid.best_estimator_
# Treinando o modelo, com os dados de treino.
classifierRF.fit(X = trainX, y = trainY)
# Calculando a acurácia do modelo para o conjunto de dados de treino.
scoreTrainRF = accuracy_score(trainY, classifierRF.predict(trainX))
# Visualizando o resultado.
print('Acurácia para os dados de treino: ' + str(scoreTrainRF))
# Calculando a acurácia do modelo para o conjunto de dados de teste.
scoreTestRF = accuracy_score(testY, classifierRF.predict(testX))
# Visualizando o resultado.
print('Acurácia para os dados de teste: ' + str(scoreTestRF))
Iremos buscar pelos melhores parâmetros, para criar um modelo com algoritmo Xgboost.
# Definindo qual conjunto de dados de treino, já escalado, deve ser utilizado e a sua variável target.
trainX = trainFeaturesSS[f]
trainY = trainTarget
# Definindo qual conjunto de dados de teste, já escalado, deve ser utilizado e a sua variável target.
testX = testFeaturesSS[f]
testY = testTarget
# Definindo os valores que devem ser testados, em cada um dos parâmetros do modelo especificado.
paramGrid = dict (
missing = [np.nan],
booster = ['gbtree'],#, 'gblinear', 'dart'],
max_depth = [4, 5],
n_estimators = [300, 350],
learning_rate = [0.025, 0.03],
nthread = [4],
subsample = [0.95, 1],
colsample_bytree = [0.95, 1],
seed = [100]
)
# Criando uma instância da classe do modelo Xgboost.
model = xgb.XGBClassifier(use_label_encoder=False,eval_metric='mlogloss')
# Criando o grid, para fazer a busca dos melhores parâmetros para o modelo.
grid = GridSearchCV(estimator = model, param_grid = paramGrid, cv = 10, verbose = True, n_jobs = -1)
# Buscando pelos melhores parâmetros para o modelo.
grid.fit(trainX, trainY)
# Exibindo a configuração, do melhor modelo treinado.
print("\n" + "Melhores Parâmetros para o Modelo:" + "\n\n", grid.best_estimator_)
# Criando o modelo, com a melhor configuração encontrada.
classifierXGB = grid.best_estimator_
# Treinando o modelo com os dados de treino.
classifierXGB.fit(X = trainX, y = trainY)
# Calculando a acurácia do modelo para o conjunto de dados de treino.
scoreTrainXGB = accuracy_score(trainY, classifierXGB.predict(trainX))
# Visualizando o resultado.
print('Acurácia para os dados de treino: ' + str(scoreTrainXGB))
# Calculando a acurácia do modelo para o conjunto de dados de teste.
scoreTestXGB = accuracy_score(testY, classifierXGB.predict(testX))
# Visualizando o resultado.
print('Acurácia para os dados de teste: ' + str(scoreTestXGB))
O melhor classificador treinado, utiliza o algoritmo XGBoost com as features transformadas pelo algoritmo StandScaler. Salvaremos as configurações desse modelo em um arquivo .sav.
# Salvando o modelo preditivo especificado.
utlml.saveModel(name = 'classifierXGB', model = classifierXGB)
# Carregando o modelo preditivo especificado.
classifierXGB = utlml.loadModel(name = 'classifierXGB')
Para analisar melhor a performance do modelo, precisamos determinar os valores das probabilidades geradas nas previsões.
# Definindo qual conjunto de dados de treino, já escalado, deve ser utilizado e a sua variável target.
trainX = trainFeaturesSS[f]
testX = testFeaturesSS[f]
# Realizando as predições das probabilidades, dos dados de treino e teste, para o modelo selecionado.
predTrainProb = classifierXGB.predict_proba(trainX)[:,1]
predTestProb = classifierXGB.predict_proba(testX)[:,1]
Iremos binarizar as previsões, e os valores a serem previstos, dos conjuntos de dados de treino e teste.
# Definindo as classes positiva e negativa da variável target.
labelPositive = 'Yes'
labelNegative = 'No'
# Criando uma lista com as categorias das classes.
labels = [labelPositive, labelNegative]
# Convertendo dados da variável target, dos dados de treino, para utilizar as labels especificadas.
trainTargetLabels = [labelPositive if t == 1 else labelNegative for t in trainTarget]
trainPredLabels = [labelPositive if t >= 0.5 else labelNegative for t in predTrainProb]
# Convertendo dados da variável target, dos dados de teste, para utilizar as labels especificadas.
testTargetLabels = [labelPositive if t == 1 else labelNegative for t in testTarget]
testPredLabels = [labelPositive if t >= 0.5 else labelNegative for t in predTestProb]
# Criando uma Confusion Matrix para avaliar as previsões feitas para os dados de treino.
cm = utlml.confusionMatrix(yTrue = trainTargetLabels, yPred = trainPredLabels)
# Exibindo a Confusion Matrix.
cm
Podemos observar, que o modelo só apresenta falsos negativos para o conjunto de dados de treino. Isto é, o modelo tende a classificar indivíduos que realizaram o churn, como não o tendo feito.
# Criando uma Confusion Matrix para avaliar as previsões feitas para os dados de teste.
cm = utlml.confusionMatrix(yTrue = testTargetLabels, yPred = testPredLabels)
# Exibindo a Confusion Matrix.
cm
Nos dados de teste, constatamos a ocorrência de falsos positivos, mas a proporção de falsos negativos continua sendo predominante.
# Plotando a Confusion Matrix dos dados de teste em um gráfico.
utlml.plotConfusionMatrix (
data = cm.drop(labels= 'classError', axis = 1),
labels = labels
)
Vamos calcular algumas estatísticas, baseadas nos resultados gerados pelo modelo, para os dados de teste.
# Calculando os scores de diferentes métricas, com base nas previsões geradas pelo modelo, para os dados de teste.
utlml.getClassificationMetrics(yTrue = testTargetLabels, predProb = predTestProb)
Finalizamos esta análise, concluindo que o algoritmo XGBoost, gerou o modelo com a melhor acurácia. Os scores alcançados para os conjuntos de dados foram:
Caso tenha alguma dúvida ou sugestão, entre em contato.